﻿@using System.ComponentModel
@using System.Text
@using System.Web.Mvc
@using SampleGenerator.Models

@helper VaryByLanguage(string csValue, string vbValue)
{
    if (ViewBag.Project.Language == CodeLanguage.Cs)
    {
        @Raw(csValue)
    }
    else if (ViewBag.Project.Language == CodeLanguage.Vb)
    {
        @Raw(vbValue)
    }
    else
    {
        throw new Exception("Invalid language '" + ViewBag.Project.Language.ToString() + "'.");
    }
}

@helper VaryByFramework(string net2Value, string net35Value, string net4Value)
    {
    if (ViewBag.Project.TargetFramework == FrameworkVersion.NET2)
    {
        @Raw(net2Value)
    }
    else if (ViewBag.Project.TargetFramework == FrameworkVersion.NET35)
    {
        @Raw(net35Value)
    }
    else if (ViewBag.Project.TargetFramework == FrameworkVersion.NET4)
    {
        @Raw(net4Value)
    }
    else
    {
        throw new Exception("Invalid target framework '" + ViewBag.Project.TargetFramework.ToString() + "'.");
    }
}

@helper VaryByVersion(string vs2005Value, string vs2008Value, string vs2010Value)
    {
    if (ViewBag.Version == VsVersion.VS2005)
    {
        @Raw(vs2005Value)
    }
    else if (ViewBag.Version == VsVersion.VS2008)
    {
        @Raw(vs2008Value)
    }
    else if (ViewBag.Version == VsVersion.VS2010)
    {
        @Raw(vs2010Value)
    }
    else
    {
        throw new Exception("Invalid version '" + ViewBag.Version.ToString() + "'.");
    }
}

@helper VaryByViewEngine(string webformsValue, string mvcValue, string razorValue)
{
    if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
    {
        @Raw(webformsValue)
    }
    else if (ViewBag.Project.ViewEngine == ViewEngine.Mvc)
    {
        @Raw(mvcValue)
    }
    else if (ViewBag.Project.ViewEngine == ViewEngine.Razor)
    {
        @Raw(razorValue)
    }
    else
    {
        throw new Exception("Invalid view engine '" + ViewBag.Project.ViewEngine.ToString() + "'.");
    }
}

@helper ActionLink(string name, string key = null)
{    
    if (key == null)
    {
        key = name;
    }

    key = key.ToLower();
    
    <strong>
        @if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
        {
            <a href="@RenderStatement("ResolveUrl(\"~/" + key + "\")")">@name</a>
        }
        else
        {
            @RenderStatement("Html.ActionLink(\"" + name + "\", \"Index\", \"" + key + "\")")
        }
    </strong> 
}

@helper InputFor(string name, string type, string style = null)
{
    if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
    {
        name = name.Substring(0, 1).ToLower() + name.Substring(1);
        
        <asp:@type ID="@name@type" runat="server"@Raw(!string.IsNullOrWhiteSpace(style) ? " style = \"" + style + "\"" : null) />
    }
    else
    {
        if (ViewBag.Project.Language == CodeLanguage.Cs)
        {
        @RenderStatement("Html." + type + "For(x => x." + name + (!string.IsNullOrWhiteSpace(style) ? ", new { style = \"" + style + "\" }" : "") + ")")
        }
        else
        {
        @RenderStatement("Html." + type + "For(Function(x) x." + name + (!string.IsNullOrWhiteSpace(style) ? ", New With { .style = \"" + style + "\" }" : "") + ")")
        }
    }
}

@helper RenderButton(string id, string cssClass, string webFormsAttributes, string nonWebFormsAttributes, string style, Func<object, HelperResult> content, bool includeWebFormsClick = true, bool forceClientButton = false)
    {
    if (ViewBag.Project.ViewEngine == ViewEngine.WebForms && !forceClientButton)
    {
        @:<asp:LinkButton ID="@id" runat="server" CssClass="@cssClass" @Raw(!string.IsNullOrEmpty(style) ? "style=\"" + style + "\"" : "") @Raw(webFormsAttributes) @(includeWebFormsClick ? VaryByLanguage("onclick=\"" + id + "_Click\"", null) : null)>
    }
    else
    {
        @:<a id="@id" @Raw(nonWebFormsAttributes.IndexOf("onclick") != -1 ? "href=\"javascript:;\"" : null) @Raw(nonWebFormsAttributes) class="@cssClass" @Raw(!string.IsNullOrEmpty(style) ? "style=\"" + style + "\"" : "")>
    }
    @content(null)

    if (ViewBag.Project.ViewEngine == ViewEngine.WebForms && !forceClientButton)
    {
        @:</asp:LinkButton>
    }
    else
    {
        @:</a>
    }

}

@helper ResolveContent(string url)
    {    
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
        {
        @RenderStatement("ResolveUrl(\"" + url + "\")")
        }
        else
        {
        @RenderStatement("Url.Content(\"" + url + "\")")        
        }    
}

@helper ResolveId(string id, bool forceClientId = false)
    {    
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms && !forceClientId)
        {
        @RenderStatement(id + ".ClientID")
        }
        else
        {
        @id
        }    
}

@helper RenderStatement(string statement, bool isRaw = false)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms || ViewBag.Project.ViewEngine == ViewEngine.Mvc)
        {
            if (ViewBag.Project.TargetFramework < FrameworkVersion.NET4 || isRaw)
            {
            @Raw("<%=" + statement + " %>")
            }
            else
            {
            @Raw("<%:" + statement + " %>")
            }
        }
        else
        {
            if (!isRaw && statement.IndexOf(' ') == -1)
            {
            @Raw("@" + statement)
            }
            else
            {
            @Raw("@" + (isRaw ? "Html.Raw" : "") + "(" + statement + ")")
            }
        }
}

@helper RenderCode(string statement, bool isOpenRazorCodeBlock = false, bool includeRazorBrackets = false)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms || ViewBag.Project.ViewEngine == ViewEngine.Mvc)
        {
        @Raw("<% " + statement + " %>")
        }
        else
        {
            //if (statement.IndexOf(' ') == -1)
            //{
            @Raw((!isOpenRazorCodeBlock ? "@" : "") + (includeRazorBrackets ? "{" : "") + statement + (includeRazorBrackets ? "}" : ""))
            //}
            //else
            //{
            //    @Raw("@(" + statement + ")")
            //}
        }
}

@helper RenderCode(HelperResult statement, bool isOpenRazorCodeBlock = false, bool includeRazorBrackets = false)
    {
    @RenderCode(statement.ToString(), isOpenRazorCodeBlock, includeRazorBrackets)
}

@helper DefineSection(string name, bool isBody = false)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms || ViewBag.Project.ViewEngine == ViewEngine.Mvc)
        {
        <asp:ContentPlaceHolder ID="@name" runat="server" />
        }
        else if (isBody)
        {
        @:@@RenderBody()
    }
        else
        {
        @:@@RenderSection("@name", false)
    }
}
@helper BeginSection(string name, bool isBody = false)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms || ViewBag.Project.ViewEngine == ViewEngine.Mvc)
        {
@:<asp:Content ContentPlaceHolderID="@name" runat="server">
    }
        else if (!isBody)
        {
            if (ViewBag.Project.Language == CodeLanguage.Cs)
            {<text>@@section @name
            {</text>}
            else
            {<text>@@Section @name</text>}
        }
}

@helper EndSection(bool isBody = false)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms || ViewBag.Project.ViewEngine == ViewEngine.Mvc)
        {
@:</asp:Content>
    }
        else if (!isBody)
        {
            if (ViewBag.Project.Language == CodeLanguage.Cs)
            {
            @:}
            }
            else
            {@:End Section
            }
        }    
}

@helper BeginForm(string id, string action, string controller, string enctype = null)
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
        {
    @:<form id="@id" runat="server">
    }
        else
        {
            if (ViewBag.Project.Language == CodeLanguage.Cs)
            {
        @RenderCode("using (Html.BeginForm(\"" + action + "\", \"" + controller + "\", FormMethod.Post, new { id = \"" + id + "\"" + (!string.IsNullOrWhiteSpace(enctype) ? ", enctype = \"" + enctype + "\"" : "") + " })) {")
            }
            else
            {
        @RenderCode("Using (Html.BeginForm(\"" + action + "\", \"" + controller + "\", FormMethod.Post, New With { .id = \"" + id + "\"" + (!string.IsNullOrWhiteSpace(enctype) ? ", .enctype = \"" + enctype + "\"" : "") + " }))")
            }
        }
}

@helper EndForm()
    {
        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
        {
    @:</form>
    }
        else
        {
            string end = VaryByLanguage("}", "End Using").ToString();

            if (ViewBag.Project.ViewEngine == ViewEngine.Mvc)
            {
            @RenderCode(end)
            }
            else
            {
            @end
            }
        }    
}

@functions
{
    public static dynamic ViewBag
    {
        get
        {
            return ((WebViewPage)WebPageContext.Current.Page).ViewBag;
        }
    }

    public static HtmlString Raw(string value)
    {
        return new HtmlString(value);
    }
    
    public static string GetFirstExtension(string path)
    {
        string fileName = Path.GetFileName(path);

        int pos = fileName.IndexOf('.');

        if (pos != -1)
        {
            string ext = fileName.Substring(pos);

            pos = ext.IndexOf('.', 1);

            if (pos != -1)
                ext = ext.Substring(0, pos);

            return ext;
        }
        else
        {
            return null;
        }
    }

    public static string ChangeExtension(string path, string extension)
    {
        string fileName = Path.GetFileName(path);

        int pos = fileName.IndexOf('.');

        if (pos != -1)
            fileName = fileName.Substring(0, pos);

        return Path.Combine(Path.GetDirectoryName(path), fileName + extension);
    }
    
    public static Dictionary<string, string> ObjectToDictionary(object value)
    {
        if (value is Dictionary<string, string>)
        {
            return (Dictionary<string, string>)value;
        }
        
        Dictionary<string, string> data = new Dictionary<string, string>();

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);

        foreach (PropertyDescriptor property in properties)
        {
            object propertyValue = property.GetValue(value);
            
            if (propertyValue is Func<object, HelperResult>)
                propertyValue = ((Func<object, HelperResult>)propertyValue)(null);
            
            if (propertyValue != null)      
            {
                if (propertyValue is bool)
                    data[property.Name] = propertyValue.ToString().ToLower();
                else
                    data[property.Name] = propertyValue.ToString();
            }
        }

        return data;
    }
    
    public static HtmlString RenderAttributes(Dictionary<string, string> attributes, bool isWebForms, bool isMultiline, CodeLanguage language)
    {
        StringBuilder sb = new StringBuilder();
        
        string[] keys = attributes.Keys.ToArray();
        
        for (int i = 0; i < keys.Length; i++)
        {
            if (sb.Length > 0)
            {
                if (!isWebForms)
                {
                    sb.Append(",");
                    
                    if (!isMultiline)
                    {
                        sb.Append(" ");
                    }
                    else
                    {
                        if (language == CodeLanguage.Vb)
                        {
                            sb.Append(" _");
                        }
                        
                        sb.Append("\r\n");
                    }
                }
                else
                {
                    sb.Append(" ");
                }
            }
            
            if (!isWebForms && language == CodeLanguage.Vb)
            {
                sb.Append(".");
            }
            
            sb.Append(keys[i]);
            
            if (!isWebForms)
            {
                sb.Append(" ");
            }
            
            sb.Append("=");

            if (!isWebForms)
            {
                sb.Append(" ");
            }
            
            string value = attributes[keys[i]];

            if (isWebForms && !value.StartsWith("\""))
                sb.Append("\"");
            
            sb.Append(value);

            if (isWebForms && !value.EndsWith("\""))
                sb.Append("\"");
        }
        
        return new HtmlString(sb.ToString());
    }  
    
    public static HtmlString RenderInitializerAttributes(Dictionary<string, string> attributes, CodeLanguage language)
    {
        string value = RenderAttributes(attributes, false, false, language).ToString();

        if (!string.IsNullOrWhiteSpace(value))
        {
            if (language == CodeLanguage.Cs)
                value = "new { " + value + "}";
            else
                value = "New With { " + value + "}";
        }

        return new HtmlString(value);
    }

    public static void RewriteHtmlAttributes(Dictionary<string, string> attributes, string componentName, CodeLanguage language)
    {
        string className;
        string style;

        attributes.TryGetValue(componentName + "CssClass", out className);
        attributes.TryGetValue(componentName + "Style", out style);

        attributes.Remove(componentName + "CssClass");
        attributes.Remove(componentName + "Style");

        Dictionary<string, string> htmlAttributes = new Dictionary<string, string>();

        if (!string.IsNullOrWhiteSpace(className))
        {
            htmlAttributes[(language == CodeLanguage.Cs ? "@" : null) + "class"] = className;
        }
        if (!string.IsNullOrWhiteSpace(style))
        {
            htmlAttributes["Style"] = style;
        }

        string value = SampleHelper.RenderInitializerAttributes(htmlAttributes, language).ToString();

        if (!string.IsNullOrWhiteSpace(value))
        {
            attributes[componentName + "HtmlAttributes"] = value;
        }
    }
        
    public static HtmlString RenderComponent(string type, object attributes = null, object htmlAttributes = null, object templates = null)
    {   
        StringBuilder sb = new StringBuilder();
        
        Dictionary<string, string> attributeDictionary = ObjectToDictionary(attributes);
        Dictionary<string, string> htmlAttributeDictionary = ObjectToDictionary(htmlAttributes);
    
        string templateString = null;
        Dictionary<string, string> templateDictionary = null;

        if (templates is string)
        {
            templateString = (string)templates;
        }
        else
        {
            templateDictionary = ObjectToDictionary(templates);
        }

        if (ViewBag.Project.ViewEngine == ViewEngine.WebForms)
        {
            attributeDictionary["runat"] = "\"server\"";

            string element;
            
            if (attributeDictionary.TryGetValue("Element", out element))
            {
                attributeDictionary["Element"] = "\"" + element.Substring(element.IndexOf(".") + 1) + "\"";
            }
            
            // TODO: handle classes
            string attributeString = RenderAttributes(attributeDictionary, true, false, ViewBag.Project.Language).ToString();
            string htmlAttributeString = RenderAttributes(htmlAttributeDictionary, true, false, ViewBag.Project.Language).ToString();
        
            sb.Append("<kw:");
            sb.Append(type);
            sb.Append(" ");
            sb.Append(attributeString);
            if (!string.IsNullOrWhiteSpace(attributeString) && !string.IsNullOrWhiteSpace(htmlAttributeString))
            {
                sb.Append(" ");
            }
            sb.Append(htmlAttributeString);

            if (string.IsNullOrWhiteSpace(templateString) && (templateDictionary == null || templateDictionary.Count == 0))
            {
                sb.Append("/>");
            }
            else
            {
                sb.Append(">");
            
                if (!string.IsNullOrWhiteSpace(templateString))
                {
                    sb.Append(templateString);
                }
                else
                {
                    foreach (string key in templateDictionary.Keys)
                    {
                        sb.Append("<" + key + ">");
                        sb.Append(templateDictionary[key]);
                        sb.Append("</" + key + ">\r\n");
                    }
                }
                sb.Append("</kw:" + type + ">");
            }
        }
        else
        {
            string startBlock = (ViewBag.Project.ViewEngine == ViewEngine.Mvc ? "<% " : "@");
            string endBlock = (ViewBag.Project.ViewEngine == ViewEngine.Mvc && ViewBag.Project.Language == CodeLanguage.Cs ? ";" : "") + (ViewBag.Project.ViewEngine == ViewEngine.Mvc ? " %>" : "");            
            string newString = (ViewBag.Project.Language == CodeLanguage.Cs ? "new" : "New");
            string renderMethod = (ViewBag.Project.ViewEngine == ViewEngine.Mvc ? "KrystalwareWebForms" : "KrystalwareRazor");
            string startLambda;
            string endLambda;
            
            if (ViewBag.Project.Language == CodeLanguage.Cs)
            {
                if (ViewBag.Project.ViewEngine == ViewEngine.Mvc)
                {
                    startLambda = "() => { %>";
                    endLambda ="<% }";
                }
                else
                {
                    startLambda = "@<text>";
                    endLambda = "</text>";
                }
            }
            else
            {
                if (ViewBag.Project.ViewEngine == ViewEngine.Mvc)
                {
                    startLambda = "Sub() %>";
                    endLambda = "<% End Sub";
                }
                else
                {
                    startLambda = "@<text>";
                    endLambda = "</text>";
                }
            }

            if (htmlAttributeDictionary.Count > 0)
            {
                attributeDictionary["HtmlAttributes"] = RenderInitializerAttributes(htmlAttributeDictionary, ViewBag.Project.Language).ToString();
            }

            if (!string.IsNullOrWhiteSpace(templateString))
            {
                attributeDictionary["Template"] =  newString + " Template(\"" + templateString + "\")";
            }
            else if (templateDictionary != null && templateDictionary.Count > 0)
            {
                foreach (string key in templateDictionary.Keys)
                {
                    attributeDictionary[key] = newString + " Template(" + startLambda + "\r\n" + templateDictionary[key] + "\r\n" + endLambda + ")";
                }
            }           

            sb.Append(startBlock + "Html." + renderMethod + "(" + newString + " " + type + "()");

            if (attributeDictionary.Count > 0)
            {
                if (ViewBag.Project.Language == CodeLanguage.Vb)
                {
                    sb.Append(" With");
                }

                sb.Append(" { ");

                if (templateDictionary != null && templateDictionary.Count > 0)
                {
                    if (ViewBag.Project.Language == CodeLanguage.Vb)
                    {
                        sb.Append("_");
                    }

                    sb.Append("\r\n");
                }

                sb.Append(RenderAttributes(attributeDictionary, false, (templateDictionary != null && templateDictionary.Count > 0), ViewBag.Project.Language));

                if (templateDictionary != null && templateDictionary.Count > 0)
                {
                    if (ViewBag.Project.Language == CodeLanguage.Vb)
                    {
                        sb.Append(" _");
                    }

                    sb.Append("\r\n");
                }  
                sb.Append(" } ");                                  
            }
            
            sb.Append(")" + endBlock);
        }
        
        return new HtmlString(sb.ToString());
    }    
}
